"""
The MIT License (MIT)
Copyright © 2022 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/micropython-tft-research
"""
from machine import SPI, Pin
from sys import exit
import st7789
import os
import math
import gc
import utime
import esp32
from libs.fontlib import FontLib
from config import Config
from drivers.five_direction_button import FiveDirectionButton_ADC, Directions
from dispatcher import Dispatcher

RESOURCE_PARTITION = '/res'


class ResourceManager(object):
	@staticmethod
	def mount_resource_partition() -> bool:
		try:
			os.umount(RESOURCE_PARTITION)
		except OSError as ose:
			if str(ose) == '[Errno 22] EINVAL':
				pass
			else:
				print(ose)

		res = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='resource')

		if res:
			os.mount(res[0], RESOURCE_PARTITION)
			return True
		else:
			return False


class TxtReader(object):
	def __init__(self, display:st7789.ST7789, txt_file:str, font_file:str):
		self.__display = display
		self.__fontlib = FontLib(font_file)
		self.__fontlib.info()

		with open(txt_file) as file:
			self.__chars = file.read().replace('\r\n', '\n')

		self.__display_width = display.width()
		self.__display_height = display.height()
		self.__char_width = self.__fontlib.font_height
		self.__char_height = self.__fontlib.font_height

		self.__chars_per_line = math.floor(self.__display_width / self.__char_width)
		self.__rows_per_page = math.floor(self.__display_height / self.__char_height)

		self.__char_buffer_array = bytearray(self.__char_width * self.__char_height * 2)

		self.pages = self.__get_pages()

		gc.collect()

	def __get_pages(self):
		col = 0
		pages = row = 1

		for char in self.__chars:
			if ord(char) in (10, 13):
				col = 0
				row += 1
				continue

			if col == self.__chars_per_line:
				col = 0
				row += 1
			
			if row > self.__rows_per_page:
				pages += 1
				col = 0
				row = 1
			
			col += 1
		
		gc.collect()

		return pages

	def __get_chars_in_page(self, page:int):
		current_page = col = 0
		row = 1
		result = []

		for char in self.__chars:
			if ord(char) in (10, 13):
				col = 0
				row += 1
				# print('')

				if current_page == page:
					result.append(char)

				continue

			if col == self.__chars_per_line:
				col = 0
				row += 1
				# print('')

			if row > self.__rows_per_page:
				if len(result) > 0:
					break

				current_page += 1
				col = 0
				row = 1
				# print('')

			# print(char, end='')
			col += 1

			if current_page == page:
				result.append(char)

		gc.collect()

		return result

	def clean(self):
		self.__display.fill(st7789.BLACK)

	def show_page(self, page:int):
		chars = self.__get_chars_in_page(page)

		# for char in chars:
		# 	print(char, end='')

		if not chars:
			return

		buffer_dict = self.__fontlib.get_characters(chars)

		x = y = 0
		self.clean()
		# self.__display.fill_rect(0, 0, self.__display_width, self.__display_height, st7789.BLACK)

		for char in chars:
			if ord(char) in (10, 13):
				x = 0
				y += self.__char_height
				continue

			if x == self.__chars_per_line * self.__char_width:
				x = 0
				y += self.__char_height

			if y >= self.__rows_per_page * self.__char_height:
				break

			char_buffer = buffer_dict[ord(char)]

			self.__display.map_bitarray_to_rgb565(char_buffer, self.__char_buffer_array, self.__char_width, st7789.WHITE, st7789.BLACK)
			self.__display.blit_buffer(self.__char_buffer_array, x, y, self.__char_width, self.__char_height)

			x += self.__char_width

		del buffer_dict
		del chars
		gc.collect()


def initialize_display():
	spi = SPI(
		1,
		baudrate=40000000,
		polarity=1,
		sck=Pin(Config.Pins.SCL),
		mosi=Pin(Config.Pins.SDA)
	)

	display = st7789.ST7789(
		spi, 240, 240,
		reset=Pin(Config.Pins.RST, Pin.OUT),
		dc=Pin(Config.Pins.DC, Pin.OUT)
	)
	display.init()

	# display.fill(st7789_cpp.GREEN)
	# display.fill_circle(120, 120, 80, st7789_cpp.color565(255, 0, 0))


	# display.jpg('images/luffy_60.jpg', 60, 60, st7789_cpp.SLOW)
	# print(display.jpg_decode('images/luffy.jpg', 0, 0, 240, 240))

	return display


if __name__ == '__main__':
	if not ResourceManager.mount_resource_partition():
		print('Cannot mount resource partition')
		exit(0)

	display = initialize_display()

	button = FiveDirectionButton_ADC(Config.Pins.ADC)
	reader = TxtReader(
		display=display,
		txt_file=f'{RESOURCE_PARTITION}/chushibiao.txt',
		font_file=f'{RESOURCE_PARTITION}/fonts/chushibiao_30.bin'
	)

	current_page = 0
	reader.show_page(current_page)

	def __get_direction(single_button:False):
		global current_page

		direction = button.direction

		if direction in (Directions.NONE, Directions.LEFT, Directions.RIGHT):
			return

		if single_button:
			if direction == Directions.CENTER:
				current_page = (current_page + 1) % reader.pages
				print(f'go to page: {current_page}')

				reader.show_page(current_page)
		else:
			if direction == Directions.UP:
				current_page = (current_page - 1) % reader.pages
				print(f'back to page: {current_page}')

				reader.show_page(current_page)
			elif direction == Directions.DOWN:
				current_page = (current_page + 1) % reader.pages
				print(f'go to page: {current_page}')

				reader.show_page(current_page)

	tasks = Dispatcher()
	tasks.add_work(__get_direction, False, 200)

	# for page in range(reader.pages):
	# 	reader.show_page(page)
	# 	utime.sleep(2)
